<?php
/**
* Scribble installer.
*
* Copyright (c) 2009 James Gauld <james@jamesgauld.net>
* This file is part of Scribble.
* @license http://www.scribblecms.co.uk/license.txt
*
* @package Scribble
*/
use Buan\Config;
use Buan\Database;
use Buan\Model;
use Buan\ModelManager;
use Buan\SystemLog;
class InstallController extends ScribbleAdminController {

	/**
	* Present an overview of what's going to happen during installation and list
	* any tasks the user needs to perform before installation can take place.
	*
	* @param array Action Parameters (none supported)
	* @return View
	*/
	public function index($params) {

		// If a Site model is already available for the current site then we
		// shouldn't be here as this indicates the system has already been installed
		if(SiteManager::getCurrentSite()!==NULL) {
			SystemLog::add('Scribble is already installed for this site!', SystemLog::INFO);
			return new ScribbleAdminView();
		}

		// Determine what type of installation this will be; first-time or site.
		// The difference is slight, but important. If there are no db tables then
		// we assume it's first-time, otherwise assume it's for another site that
		// happens to be using the same database.
		$tables = ModelManager::sqlQuery('SHOW TABLES')->fetchAll(PDO::FETCH_OBJ);
		if(empty($tables)) {
			return $this->firstInstall();
		}
		else {
			return $this->siteInstall();
		}
	}

	/**
	* Present a first-time installation.
	*
	* @return ScribbleAdminView
	*/
	private function firstInstall() {

		// Prepare views
		$view = new ScribbleAdminView();
		if(!$this->init($view, TRUE)) {
			return $view;
		}
		$view->setSource(Config::get('ext.Scribble.dir.views').'/scribble/install/first-install.tpl.php');

		/* ------------------------- Steps required before installation can start */
		// Test: Is database available?
		$preSteps = array();
		try {
			$db = Database::getConnection();
		}
		catch(Exception $e) {
			$preSteps[] = 'create-database';
		}

		// Test: Have you told Scribble where to upload files, and is it writeable
		$ud = Config::get('ext.Scribble.uploads.dir');
		if(!is_dir($ud) || !is_writeable($ud)) {
			$preSteps[] = 'setup-upload-path';
		}

		// Test: Is data folder writable
		$dataDir = Config::get('ext.Scribble.dir.data');
		if(!is_writeable($dataDir)) {
			$preSteps[] = 'setup-data-dir';
		}

		// Result
		if(!empty($preSteps)) {
			$view->preSteps = $preSteps;
			return $view;
		}
		$view->dbInfo = Database::getConnectionInfo();

		/* ------------------------------------------------- Perform installation */
		if(!empty($_POST)) {

			// Validate parameters
			if(empty($_POST['email']) || !preg_match("/^[^@]+@.+?\..+$/i", $_POST['email'])) {
				SystemLog::add('Please provide a valid email address.', SystemLog::WARNING);
			}

			// Install
			else {
				return $this->firstInstallGo($_POST['email']);
			}
		}

		// Result
		return $view;
	}

	/**
	* Install the components for a fresh, first-time installation.
	*
	* @param string The email address of the system administrator
	* @return View
	*/
	private function firstInstallGo($email) {

		// Prepare views
		$view = new ScribbleAdminView();
		if(!$this->init($view, TRUE)) {
			return $view;
		}
		$view->setSource(Config::get('ext.Scribble.dir.views').'/scribble/install/first-install-go.tpl.php');

		// Install tables
		try {
			$sql = new SqlDumpIterator(file_get_contents(Config::get('ext.Scribble.dir.resources').'/db-schema.sql'));
			$tblPrefix = Config::get('ext.Scribble.dbTablePrefix');
			foreach($sql as $q) {
				$q = preg_replace("/^DROP TABLE IF EXISTS\s+`([a-z_0-9]+)`/i", "DROP TABLE IF EXISTS `".$tblPrefix."$1`", $q);
				$q = preg_replace("/^CREATE TABLE\s+`([a-z_0-9]+)`/im", "CREATE TABLE `".$tblPrefix."$1`", $q);
				ModelManager::sqlQuery($q);
			}
			SystemLog::add('Database tables were successfully installed!', SystemLog::INFO);
		}
		catch(Exception $e) {
			SystemLog::add($e->getMessage(), SystemLog::WARNING);
			return new ScribbleAdminView();
		}

		// Prepare the system data folder
		$dataDir = Config::get('ext.Scribble.dir.data');
		$rsDir = Config::get('ext.Scribble.dir.resources');
		if(!copy("{$rsDir}/.htaccess-deny-all", "{$dataDir}/.htaccess")) {
			SystemLog::add('Failed to copy the .htaccess file to the data folder.', SystemLog::WARNING);
			return new ScribbleAdminView();
		}

		// Create 'Administrator' role and grant ALL privileges globally
		$rAdmin = Model::create('Role');
		$rAdmin->title = 'Administrator';
		$rAdmin->description = 'Users in this group have unlimited control over everything';
		ScribbleAuth::grant($rAdmin, '*');

		// Create an initial user so we can access the Scribble admin UI
		$user = Model::create('User');
		$user->email = $email;
		$user->displayname = 'Administrator';
		$user->hashsalt = UserModel::generateHashSalt();
		$loginPassword = UserModel::generateRandomPassword();
		$user->password = $user->encryptPassword($loginPassword);
		$user->addRelatives($rAdmin);
		if(!$user->getModelManager()->save($user)) {
			SystemLog::add('Failed to create an initial user and role.', SystemLog::WARNING);
			return new ScribbleAdminView();
		}
		$view->loginEmail = $email;
		$view->loginPassword = $loginPassword;

		// Create a site model to represent the current site
		$site = Model::create('Site');
		$site->prefix = Config::get('ext.Scribble.site.prefix');
		if(!$site->getModelManager()->save($site)) {
			SystemLog::add(array('Failed to create a Site model for %s.', $site->prefix), SystemLog::WARNING);
			return new ScribbleAdminView();
		}

		// Store installed version in registry
		ScribbleRegistry::set('ext.Scribble.version', Config::get('ext.Scribble.version'));

		// Result
		return $view;
	}

	/**
	* Present a site-installation into an existing database.
	*
	* @return ScribbleAdminView
	*/
	private function siteInstall() {

		// Prepare views
		$view = new ScribbleAdminView();
		if(!$this->init($view, TRUE)) {
			return $view;
		}
		$view->setSource(Config::get('ext.Scribble.dir.views').'/scribble/install/site-install.tpl.php');

		/* ------------------------------------------------- Perform installation */
		if(!empty($_POST)) {
			return $this->siteInstallGo();
		}

		// Result
		return $view;
	}

	/**
	* Install the components for single-site installation.
	*
	* @return View
	*/
	private function siteInstallGo() {

		// Prepare views
		$view = new ScribbleAdminView();
		if(!$this->init($view, TRUE)) {
			return $view;
		}
		$view->setSource(Config::get('ext.Scribble.dir.views').'/scribble/install/site-install-go.tpl.php');

		// Create a site model to represent the current site
		$site = Model::create('Site');
		$site->prefix = Config::get('ext.Scribble.site.prefix');
		if(!$site->getModelManager()->save($site)) {
			SystemLog::add(array('Failed to create a Site model for %s.', $site->prefix), SystemLog::WARNING);
			return new ScribbleAdminView();
		}

		// Result
		return $view;
	}
}
?>